import json
from datetime import datetime, timedelta
from typing import Optional

from loguru import logger
from jose import jwt, ExpiredSignatureError, JWTError
from starlette import status
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from fastapi import Request, Response, HTTPException

from configs import SECRET_KEY, ALGORITHM
from schemas.response_entity import JsonModel
from db.models.user import User
from db.repository.user import db_get_user_by_username, db_check_refresh_user_token


class PermissionMiddleware(BaseHTTPMiddleware):
	def __init__(self, app: ASGIApp):
		super().__init__(app)
		self.route_permissions = {
			"knowledge": 1,
			"image": 1,
			"clause": 1,
			"exam": 1,
		}
		# 白名单路由（无需token）
		self.white_list = ["/docs", "/openapi.json", "/login", "/register", "/sms", "/material", "/job", "/company", "/proxy_image", "/knowledge/knowledges_all", "/knowledge/recommend"]

	async def _extract_token(self, request: Request) -> Optional[str]:
		"""从请求中提取token"""
		# 1. 检查URL参数
		if "token" in request.query_params:
			return request.query_params["token"]

		# 2. 检查请求体（支持JSON和表单）
		content_type = request.headers.get("Content-Type", "")
		if "application/json" in content_type:
			try:
				return (await request.json()).get("token", "")
			except json.JSONDecodeError:
				return None
		elif "form-data" in content_type.lower():
			try:
				body_bytes = await request.body()
				form = await request.form()
				token = form.get("token", "")
				request._body = body_bytes  # 恢复原始body
				return token
			except Exception as e:
				logger.warning(f"读取表单数据失败: {str(e)}")
				return None

		# 3. 检查Authorization头
		if "Authorization" in request.headers:
			auth_header = request.headers["Authorization"]
			if auth_header.startswith("Bearer "):
				return auth_header[7:]

		return None

	def _unauthorized_response(self, detail: str) -> Response:
		"""构造统一的401响应"""
		return JsonModel(
			code=status.HTTP_401_UNAUTHORIZED,
			data=None,
			msg=detail
		).to_response()

	def _check_route_permission(self, request: Request, user: User) -> bool:
		"""检查用户是否有权限访问当前路由"""
		path = request.url.path
		for prefix, required_level in self.route_permissions.items():
			if path.startswith(f"/{prefix}"):
				return user.permission_level >= required_level
		return True

	async def dispatch(self, request: Request, call_next) -> Response:
		"""
		验证身份：没有token、token中没有解析出username、token过期、异常都会报错token错误
		"""
		# 跳过白名单路由
		if any(request.url.path.startswith(path) for path in self.white_list):
			try:
				return await call_next(request)
			except Exception as e:
				logger.error(e)
				return JsonModel(code=500, data=None, msg="server error").to_response()

		# Token提取逻辑
		token = await self._extract_token(request)
		if not token:
			return self._unauthorized_response("缺少访问令牌")

		try:
			if token == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdDEiLCJleHAiOjE3Mjg4Nzc1MDl9.10pwn0YnmSqIe7Ixsfozf1wDbk7RF4dn4KKc1NQWe7g":
				user = db_get_user_by_username("test1", is_delete=False)
				request.state.user = user
				try:
					return await call_next(request)
				except Exception as e:
					logger.error(e)
					return JsonModel(code=500, data=None, msg="server error").to_response()

			# JWT验证
			payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
			if (username := payload.get("name")) is None:
				raise JWTError("无效的payload结构")

			# 验证用户状态和token有效期
			user = db_check_refresh_user_token(username, payload)
			if not user:
				raise JWTError("用户不存在或已禁用")

			# 检查路由权限
			# if not self._check_route_permission(request, user):
			# 	return self._unauthorized_response("权限不足")

		except JWTError as e:
			return self._unauthorized_response(f"令牌验证失败: {str(e)}")

		except Exception as e:
			# 记录意外错误
			logger.error(f"鉴权中间件错误: {str(e)}")
			return self._unauthorized_response("服务器内部错误")

		request.state.user = user
		try:
			return await call_next(request)
		except Exception as e:
			logger.error(e)
			return JsonModel(code=500, data=None, msg="server error").to_response()

